#!/usr/bin/python3
# -*- coding: UTF-8 -*-
"""
@Project : SIM7600CE-REST
@File    : sim_handler.py
@Author  : Mr.Cai
@Date    : 2024/01/22 21:00
pip install paho-mqtt
"""
import serial
import time
import paho.mqtt.client as mqtt
from datetime import datetime
import re
import requests
import json
from serial.serialutil import SerialException


class SimHandler:
    """
    SIM7600CE设备读取AT状态应用
    """

    def __init__(self):
        # 短信存到设备中，目前似乎只可以接收255条信息
        self.send_at_command('AT+CPMS="ME","ME","ME"')
        # 设置短信的通知和存储模式
        self.send_at_command('AT+CNMI=2,2,0,0,0')
        
        # 开始初始化设置mqtt的client
        self.client = mqtt.Client()  # 将client作为类的一个属性
        self.client.username_pw_set(username="admin", password="qifu-cloud.com")
        self.client.on_connect = self.__on_connect  # 这里只需要传入函数名
        self.client.on_message = self.__on_message  # 这里也是
        self.client.connect('139.196.197.222', 1883, 600)  # 600为keepalive的时间间隔
        self.client.subscribe('sim-for-python', qos=0)
        print("SimHandler is running")

    # 定义开发板的端口信息
    port = '/dev/ttyS0'
    baudrate = 115200
    # 初始化全局对象
    ser = serial.Serial(port, baudrate)
    # 全局变量
    # 是否有新短信
    has_new_message = False
    # 是否正在响铃
    is_ringing = False
    # 是否有新未接来电
    has_missed_call = False
    # 是否通话中
    is_on_call = False
    # 短信容量是否已满
    # is_message_full = False
    # 是否在持续阅读短信
    is_continue_reading_message = False
    # 短信发件人
    continue_message_sender = ''
    # 短信发件时间
    continue_message_create_time = ''
    # 电话呼叫的时间
    telephone_caller_time = ''
    # 电话呼叫人的号码
    telephone_caller_number = ''
    # 扩展板是否已经就绪
    is_extension_board_ready = True


    def publish_mqtt_message(self, topic, payload, qos):
        # mq发布消息
        self.client.publish(topic, payload, qos)

    def __on_connect(self, client, userdata, flags, rc):
        """mqtt获得连接时触发"""
        print("MQTT Connected with result code: " + str(rc))

    def __on_message(self, client, userdata, msg):
        """mqtt收到消息时触发"""
        print("MQTT message:\t" + msg.topic + " " + str(msg.payload))
        
    def handle_received_message(self, txt):
        # sourcery skip: use-getitem-for-re-match-groups
        """处理响应的txt内容，识别不同的响应进入不同的逻辑"""
        self.is_extension_board_ready = False
        if txt.startswith("+CMGL"):
            # print("正在获取短信列表，识别短息状态，发件人，发件时间:\n", txt)
            # 定义正则表达式模式
            pattern = r'\+CMGL: (\d+),"([^"]*)","([^"]*)","[^"]*",("(\d{2}/\d{2}/\d{2},\d{2}:\d{2}:\d{2})\+?\d*")'
            match = re.search(pattern, txt)
            if match:
                index, status, sender, _ ,datetime_str = match.groups()
                self.init_time_and_sender_for_sms(datetime_str, sender)
            else:
                print(f"没有找到匹配的短信记录。{txt}")
            self.is_continue_reading_message = True
        elif txt.startswith("+CMT"):
            self.has_new_message = True
            print("收到新短信，识别短息状态，发件人，发件时间:\n", txt)
            # 定义正则表达式模式
            match = re.search(r'\+CMT: "(.*?)",.*,"(\d{2}/\d{2}/\d{2},\d{2}:\d{2}:\d{2}).*"', txt)
            if match:
                sender = match.group(1)
                datetime_str = match.group(2)
                self.init_time_and_sender_for_sms(datetime_str, sender)
            else:
                print(f"没有找到匹配的短信记录。{txt}")
            self.is_continue_reading_message = True
        elif self.is_continue_reading_message and "+CMT:" not in txt and "+CMGL" not in txt:
            self.post_data_by_rest(category="sms", content=self.hex2str(txt), encrypt=txt, timestamp=self.continue_message_create_time,
                            fromnumber=self.continue_message_sender, tonumber="1324817941")
            self.continue_message_sender = ''
            self.continue_message_create_time = ''
            self.is_continue_reading_message = False
            self.has_new_message = False
        elif "VOICE CALL: BEGIN" in txt:
            self.is_on_call = True
            print("已经接通电话，将发送通知给远程")
            self.post_data_by_rest(category="call", content="自动接听了一个电话", encrypt="",timestamp="接收到电话的时间",
                            fromnumber="未捕捉", tonumber="1324817941")
        elif "NO CARRIER" in txt:
            self.is_on_call = False
            print("已经挂断电话，将发送通知给远程")
            self.post_data_by_rest(category="call", content="通话或拨号已经挂断", encrypt="", timestamp="挂断通话的时间",
                            fromnumber="未捕捉", tonumber="1324817941")
        elif "RING" in txt:
            self.handle_call_when_ring()
        else:
            print(txt)
        self.is_extension_board_ready = True

    def handle_call_when_ring(self):
        """来电话的时候接电话"""
        self.is_ringing = True
        print("来电话了，已经发送接听命令，即将接听")
        # 响铃2秒后开始接听
        time.sleep(2)
        self.send_at_command('ATA')
        self.send_at_command('AT+CLIP=1')
        self.send_at_command('AT+CSDVC=1')
        # 等待3秒后开始播放声音
        time.sleep(3)
        self.send_at_command('AT+CCMXPLAYWAV="D:/wav/liuyan.wav",1')
        self.telephone_caller_time = datetime.now().strftime("%Y-%m-%d, %H:%M:%S")

    def init_time_and_sender_for_sms(self, datetime_str, sender):
        """通过传入的发送者和时间初始化到类的属性中"""
        dt = datetime.strptime(datetime_str, "%y/%m/%d,%H:%M:%S")
        received_time = dt.strftime("%Y-%m-%d %H:%M:%S")
        self.continue_message_sender = sender
        self.continue_message_create_time = received_time


    def hex2str(self, code_str):
        # sourcery skip: remove-redundant-exception, simplify-single-exception-tuple
        """将设备上的短信转换成文本"""
        if len(code_str) > 7 and len(code_str) % 2 == 0:  # 确保 code_str 的长度是偶数
            try:
                bytes_object = bytes.fromhex(code_str)
                text = bytes_object.decode('utf-16-be')
            except (ValueError, UnicodeDecodeError) as e:  # 捕获可能的错误
                print(f"转换 {code_str} 出错： {e}")
                text = code_str
        else:
            text = code_str
        return text


    def post_data_by_rest(self, category, content, encrypt, timestamp, fromnumber, tonumber="13248179431"):
        """通过rest发送通知内容到远程"""
        # 数据构造函数
        data = {
            "type": "notice",
            "category": category,
            "content": content,
            "encrypt": encrypt,
            "timestamp": timestamp,
            "from": fromnumber,
            "to": tonumber,
            "url": ""
        }

        print(f"短信推送 - 发件人： {fromnumber}, 时间： {timestamp}, 内容: {content}")
        # 将数据转换为json格式
        data_json = json.dumps(data)

        # 设置请求头
        headers = {'Content-Type': 'application/json'}

        print("data_json: ", data_json)
        # 发送POST请求
        response = requests.post('http://cha-wechat.cha1024.com/rest/notice/simPostByPython',
                                data=data_json, headers=headers)
        print("response: ", response.text)

        # 返回响应
        return response


    def send_at_command(self, command, response_wait=1):
        """发送AT命令，如果不空闲则直到空闲时再执行命令"""
        self.ser.write((command + '\r\n').encode())
        time.sleep(response_wait)
        while self.ser.inWaiting():
            txt = self.ser.readline().decode().strip()
            while not self.is_extension_board_ready:  # 等待is_extension_board_ready变为True
                time.sleep(0.5)  # 可依据具体情况调整等待时长
            self.handle_received_message(txt=txt)


    def main(self):
        try:
            self.client.loop_start()  # 非阻塞方式运行MQTT client
            while True:
                # 发送获取未读短信命令，以便于轮询状态
                self.send_at_command('AT+CMGL="REC UNREAD"')
                time.sleep(5)

        except SerialException as e:
            print(f"串行通信出错：{e}")
        except KeyboardInterrupt:
            print("\n项目已经手动停止")
            self.client.loop_stop()  # 关闭MQTT client
        finally:
            self.ser.close()
            self.client.loop_stop()  # 关闭MQTT client

